#ifndef __DAF_MODEL_H__
#define __DAF_MODEL_H__

#if defined(ALPINE) || defined(OE)
#include <json/json.h>
#else
#include <jsoncpp/json/json.h>
#endif

#include "DeviceAgentMessage.pb.h"

#include <string>
#include <vector>
#include <mutex>
#include <map>

namespace Gazella {
namespace Daf {

class DafModel {
private:
    DafModel();
    ~DafModel();

public:
    static DafModel* get_instance();

    bool load_tsl(const std::string& tsl_file);

    std::vector<DeviceAgentModel::DeviceAgentProperty> get_properties();
    bool get_property(const std::string& identifier, DeviceAgentModel::DeviceAgentProperty& property);
    bool set_property(const std::string& identifier, const DeviceAgentModel::DeviceAgentProperty& property);

    std::vector<DeviceAgentModel::DeviceAgentEvent> get_events();
    bool get_event(const std::string& identifier, DeviceAgentModel::DeviceAgentEvent& event);

    std::vector<DeviceAgentModel::DeviceAgentInterface> get_services();
    bool get_service(const std::string& identifier, DeviceAgentModel::DeviceAgentInterface& service);

    std::vector<DeviceAgentMessage::DeviceAgentAbilityElement> get_abilities();
    std::vector<DeviceAgentMessage::DeviceAgentAbilityElement> get_abilities(DeviceAgentMessage::DeviceAgentAbilityTypeEnums type);
    bool get_ability(const std::string& identifier, DeviceAgentMessage::DeviceAgentAbilityElement& ability);

private:
    //property
    DeviceAgentModel::DeviceAgentProperty __parse_property_datatype_boolean(const Json::Value& property);
    DeviceAgentModel::DeviceAgentProperty __parse_property_datatype_float(const Json::Value& property);
    DeviceAgentModel::DeviceAgentProperty __parse_property_datatype_double(const Json::Value& property);
    DeviceAgentModel::DeviceAgentProperty __parse_property_datatype_int(const Json::Value& property);
    DeviceAgentModel::DeviceAgentProperty __parse_property_datatype_int64(const Json::Value& property);
    DeviceAgentModel::DeviceAgentProperty __parse_property_datatype_string(const Json::Value& property);
    DeviceAgentModel::DeviceAgentProperty __parse_property_datatype_enum(const Json::Value& property);
    DeviceAgentModel::DeviceAgentProperty __parse_property_datatype_struct(const Json::Value& property);
    DeviceAgentModel::DeviceAgentProperty __parse_property_datatype_timestamp(const Json::Value& property);
    DeviceAgentModel::DeviceAgentProperty __parse_property_datatype_base64(const Json::Value& property);
    DeviceAgentModel::DeviceAgentProperty __parse_property_datatype_url(const Json::Value& property);
    DeviceAgentModel::DeviceAgentProperty __parse_property_datatype_array(const Json::Value& property);
    DeviceAgentModel::DeviceAgentProperty __parse_property_datatype(const Json::Value& property);
    bool __parse_properties(const Json::Value& properties);

    //event
    DeviceAgentModel::DeviceAgentEvent __parse_event(const Json::Value& event);
    bool __parse_events(const Json::Value& events);

    //service
    DeviceAgentModel::DeviceAgentInterface __parse_service(const Json::Value& service);
    bool __parse_services(const Json::Value& services);

    //ability
    DeviceAgentMessage::DeviceAgentAbilityRender  __parse_ability_render (const Json::Value& render);

    DeviceAgentMessage::DeviceAgentAbilityElement __parse_ability_inner  (const Json::Value& ability);
    DeviceAgentMessage::DeviceAgentAbilityElement __parse_ability_state  (const Json::Value& ability);
    DeviceAgentMessage::DeviceAgentAbilityElement __parse_ability_param  (const Json::Value& ability);
    DeviceAgentMessage::DeviceAgentAbilityElement __parse_ability_event  (const Json::Value& ability);
    DeviceAgentMessage::DeviceAgentAbilityElement __parse_ability_video  (const Json::Value& ability);
    DeviceAgentMessage::DeviceAgentAbilityElement __parse_ability_switch  (const Json::Value& ability);
    DeviceAgentMessage::DeviceAgentAbilityElement __parse_ability_command(const Json::Value& ability);
    DeviceAgentMessage::DeviceAgentAbilityElement __parse_ability_combox (const Json::Value& ability);
    bool __parse_abilities(const Json::Value& abilities);

private:
    std::string m_version;
    std::string m_thing;

    std::mutex m_properties_lock;
    std::map<std::string, DeviceAgentModel::DeviceAgentProperty>         m_properties;
    std::map<std::string, DeviceAgentModel::DeviceAgentEvent>            m_events;
    std::map<std::string, DeviceAgentModel::DeviceAgentInterface>        m_services;
    std::map<std::string, DeviceAgentMessage::DeviceAgentAbilityElement> m_abilities;
};
} // namespace Daf
} // namespace Gazella

#endif